﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Box2D.XNA;

public struct CollisionInfo
{
    public float x, y;
    public float width, length;

    public CollisionInfo(float x, float y, float width, float length)
    {
        this.x = x;
        this.y = y;
        this.width = width;
        this.length = length;
    }
}
public struct Point
{
    public int x, y;
    public Point (int x, int y){
        this.x=x; 
        this.y=y;
    }
}
/// <summary>
/// The Sprite class represents one character, which has its own position and animations
/// </summary>
public class Sprite
{
    public enum AnimationState { Start, Loop, End };
    public Dictionary<String, SortedDictionary<int, Double>> animations;

    int posX, posY;
    float mass;
    protected int spritePanel;
    protected int panelDimensionX;
    protected int panelDimensionY;
    protected int panelWidth;
    protected int panelLength;

    protected Dictionary<String, SpriteSheet> spriteSheets;
    protected Dictionary<String, String> stateSpriteSheetMap;

    protected int animationFrame;
    double frameNumber;
    protected double animationTime;
    protected double topSpeed;
    AnimationState animationState;
    
    protected String state;
    public enum Facing {Right, Left};
    protected Facing facing;
    protected Game game;
    protected Body spriteBody;
    protected ushort mask;
    protected float health = 100;
    protected bool isAlive = true;
    protected Dictionary<KeyValuePair<string, int>, CollisionInfo> collisionObjects;
    List<Body> hitBoxes;

    //todo: hard code topspeed or list all possible topspeeds as mem vars

    public Sprite(Vector2 position, String [] filenames, Game game, ushort mask)
    {
        this.game = game;
        topSpeed = 10; //oddly, not used
        state = "stand";
        facing = Facing.Right;
        frameNumber = 0;
        animationTime = 0.0;
        animations = new Dictionary<string, SortedDictionary<int, double>>();
        spriteSheets = new Dictionary<string, SpriteSheet>();
        stateSpriteSheetMap = new Dictionary<string, string>();
        this.mask = mask;

        hitBoxes = new List<Body>();
        

    }

    public Texture2D getSpriteSheet() { return spriteSheets[stateSpriteSheetMap[state]].getSpriteSheet(); }
    public int getPanelDimensionX() { return spriteSheets[stateSpriteSheetMap[state]].getDimensionX(); }
    public int getPanelDimensionY() { return spriteSheets[stateSpriteSheetMap[state]].getDimensionY(); }
    public int getPanelWidth() { return spriteSheets[stateSpriteSheetMap[state]].getSpriteWidth(); }
    public int getPanelLength() { return spriteSheets[stateSpriteSheetMap[state]].getSpriteHeight(); }
    public int getAnimationFrame() { return animationFrame; }
    public Body getSpriteBody() { return spriteBody; }
    public bool getIsAlive() { return isAlive; }
    public float getHealth() { return health; }

    public void intialize(String setupFilePath, ContentManager Content)
    {
        
        string[] setupFile = System.IO.File.ReadAllLines(setupFilePath);
        /* character setup file
         * first line is the sprite sheet path
         * number of panels X and Y
         */
       // spriteSheet=Content.Load<Texture2D>(setupFile[0]);
        panelDimensionX = Convert.ToInt32(setupFile[1]);
        panelDimensionX = Convert.ToInt32(setupFile[2]);
       
    }

    public virtual void update(GameTime gameTime, List<ButtonAction> buttonsPressed) {}
    public void updateFrame(GameTime gameTime)
    {
        //based on animaiton, update the amount of time
        //if the time has passed the time for that frame go to next frame
        //if passed the next frame do to first frame
        SortedDictionary <int, double> currentAnim = animations[state];

        animationTime += gameTime.ElapsedGameTime.TotalSeconds;
        if (animationTime >= currentAnim[animationFrame])
        {
            animationTime -= currentAnim[animationFrame];
            animationFrame++;
            if (animationFrame > currentAnim.Last().Key)
            {
                animationFrame = currentAnim.First().Key;
            }
        }
    }

    public void addFixture(float x, float y, float width, float length) {
        Body body;
        
        BodyDef bodyDef = new BodyDef();
        //bodyDef.type = BodyType.Dynamic;
        Vector2 position = new Vector2(getSpriteBody().GetWorldPoint(new Vector2(0)).X+x, getSpriteBody().GetWorldPoint(new Vector2(0)).Y+y);
        bodyDef.position = position;
        body = game.getWorld().CreateBody(bodyDef);

        PolygonShape dynamicBox = new PolygonShape();
        dynamicBox.SetAsBox(width/2, length/2);

        FixtureDef fixtureDef = new FixtureDef();

        fixtureDef.shape = dynamicBox;
        fixtureDef.density = .0002f;
        body.ResetMassData();
        fixtureDef.friction = .0f;
        fixtureDef.isSensor = true;
        fixtureDef.filter.maskBits = mask;
        
        body.CreateFixture(fixtureDef);

        hitBoxes.Add(body);
    }
    public void removeFixtures()
    {
        foreach (Body hitBox in hitBoxes)
        {
            ContactEdge conList = hitBox.GetContactList();
            while (conList != null)
            {
                Sprite attacked = (Sprite)conList.Contact.GetFixtureA().GetUserData();
                attacked.health -=5;
                System.Diagnostics.Debug.Write(attacked.health); 
                System.Diagnostics.Debug.Flush();

                conList = conList.Next;
            }
            
        }
        foreach (Body hitBox in hitBoxes)
        {
            game.getWorld().DestroyBody(hitBox);
        }
        hitBoxes.Clear();
    }
}